from flask import Flask
from flask_bootstrap import Bootstrap
from flask_wtf import CSRFProtect
from flask_migrate import Migrate
from flask_moment import Moment
from flask_mail import Mail

from config import CONFIG_MAPPING
from utils.middlewares import session_authentication
from models import db

# 定义在工厂函数外是为了方便被导入使用，之后再到工厂函数中初始化
mail = Mail()  # flask-mail
bootstrap = Bootstrap()  # flask-bootstrap
migrate = Migrate()  # flask-migrate
moment = Moment()  # flask-moment


def create_flask_app(environment):
    """
    生成应用实例
    :param environment: 环境名
    :return: 应用实例
    """
    # 生成Flask实例，并指定模板文件夹和静态文件夹的位置
    app = Flask(__name__, template_folder='../templates', static_folder='../static')

    # 根据环境名加载相应的配置
    app.config.from_object(CONFIG_MAPPING.get(environment))

    return app


def create_app(environment='development'):
    """
    初始化应用实例的工厂函数
    :param environment: 环境名
    :return: 应用实例
    """
    # 生成应用实例
    app = create_flask_app(environment)

    # 初始化flask拓展
    bootstrap.init_app(app)
    db.init_app(app)
    migrate.init_app(app, db)
    moment.init_app(app)
    mail.init_app(app)
    # todo:csrf，books蓝图用到的，实际不需要
    CSRFProtect(app)  # flask-wtf csrf

    # 注册中间件（钩子函数）
    app.before_request(session_authentication)

    # 注册蓝图，并指定蓝图URL前缀（注册蓝图一般都放在最后）
    from .users import user_bp  # users蓝图提供用户系统相关功能
    app.register_blueprint(user_bp, url_prefix='/users')
    from apps.books import book_bp  # books蓝图是demo，没有实际意义
    app.register_blueprint(book_bp, url_prefix='/books')
    from apps.duowan import duowan_bp  # duowan蓝图提供图库相关的功能
    app.register_blueprint(duowan_bp, url_prefix='/duowan')
    from apps.online_tools import online_tools_bp
    app.register_blueprint(online_tools_bp, url_prefix='/oltools')
    from apps.documents import document_bp
    app.register_blueprint(document_bp, url_prefix='/documents')
    from apps.background import background_bp
    app.register_blueprint(background_bp, url_prefix='/background')
    from apps.errors import error_bp
    app.register_blueprint(error_bp, url_prefix='/errors')

    return app
